/*+***********************************************************************************
 Filename: 9k_mcu01_mycore_v01\src\mem\zh_dprom_v01.v
 Description: dual-port rom with sync read clock implement by verilog.
   With initial code instructions.
   pos-edge of clk latch the address.
              
 Modification:
   2025.08.17 Creation   H.Zheng

Copyright (C) 2025  Zheng Hui (hzheng@gzhu.edu.cn)

License: MulanPSL-2.0

***********************************************************************************-*/

module zh_dprom_v01 #(parameter ROM_SIZE_IN_KB=1)(
	input wire clk, //lock address clock
  input wire [clogb2(ROM_SIZE_IN_KB*256-1)-1:0] addr_a,
  output wire [31:0] dout_a,
  input wire [clogb2(ROM_SIZE_IN_KB*256-1)-1:0] addr_b,
  output wire [31:0] dout_b

);

  //storage
  reg [7:0] BRAM[0:ROM_SIZE_IN_KB*1024-1];

  initial begin
    $readmemh("code.txt", BRAM);
  end

  reg [clogb2(ROM_SIZE_IN_KB*256-1)-1:0] addr_a_r, addr_b_r;
  always @(posedge clk) begin
    addr_a_r <= addr_a;
    addr_b_r <= addr_b;
  end
  
  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_a_b0 = {addr_a_r,2'b00};
  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_a_b1 = {addr_a_r,2'b01};
  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_a_b2 = {addr_a_r,2'b10};
  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_a_b3 = {addr_a_r,2'b11};

  assign dout_a = { BRAM[addr_a_b3], BRAM[addr_a_b2], BRAM[addr_a_b1], BRAM[addr_a_b0]};

  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_b_b0 = {addr_b_r,2'b00};
  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_b_b1 = {addr_b_r,2'b01};
  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_b_b2 = {addr_b_r,2'b10};
  wire [clogb2(ROM_SIZE_IN_KB*256-1)+1:0] addr_b_b3 = {addr_b_r,2'b11};

  assign dout_b = { BRAM[addr_b_b3], BRAM[addr_b_b2], BRAM[addr_b_b1], BRAM[addr_b_b0]};


  //
  function integer clogb2;
    input integer depth;
      for (clogb2=0; depth>0; clogb2=clogb2+1)
        depth = depth >> 1;
  endfunction

endmodule